package org.finesys.common.netty.websocket.stomp.support;

import static org.finesys.common.netty.websocket.constants.HandlerName.HTTP_AGGREGATOR;
import static org.finesys.common.netty.websocket.constants.HandlerName.HTTP_CODEC;
import static org.finesys.common.netty.websocket.constants.HandlerName.IDLE_ENVET;
import static org.finesys.common.netty.websocket.constants.HandlerName.IDLE_TIMEOUT;
import static org.finesys.common.netty.websocket.constants.HandlerName.STOMP_AGGREGATOR;
import static org.finesys.common.netty.websocket.constants.HandlerName.STOMP_DECODER;
import static org.finesys.common.netty.websocket.constants.HandlerName.STOMP_ENCODER;
import static org.finesys.common.netty.websocket.constants.HandlerName.STOMP_HANDLER;
import static org.finesys.common.netty.websocket.constants.HandlerName.WEBSOCKET_HANDLER;
import static org.finesys.common.netty.websocket.constants.WebConfigConstant.MAX_FRAME_SIZE;

import java.util.Arrays;

import javax.net.ssl.SSLException;

import org.finesys.common.netty.websocket.handler.CommonChannelIdleTimeoutHandler;
import org.finesys.common.netty.websocket.stomp.constants.StompVersion;
import org.finesys.common.netty.websocket.stomp.handler.StompServerHandler2;
import org.finesys.common.netty.websocket.support.WebSocketEndpointConfig;
import org.finesys.common.netty.websocket.util.SslUtils;
import org.springframework.util.ObjectUtils;

import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.cors.CorsConfig;
import io.netty.handler.codec.http.cors.CorsConfigBuilder;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.codec.stomp.StompSubframeAggregator;
import io.netty.handler.codec.stomp.StompSubframeDecoder;
import io.netty.handler.codec.stomp.StompSubframeEncoder;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.concurrent.EventExecutorGroup;

/**
 * StompWebSocket服务器管理类，创建websocket服务和优雅的关闭服务
 */
public class StompWebSocketInitializer extends ChannelInitializer<Channel> {

    private final StompWebSocketEndpointEventServer stompWebSocketEndpointEventServer;
    private final WebSocketEndpointConfig webSocketEndpointConfig;
    private final EventExecutorGroup eventExecutorGroup;
    private SslContext sslContext;
    private CorsConfig corsConfig;

    public StompWebSocketInitializer(StompWebSocketEndpointEventServer stompWebSocketEndpointEventServer, WebSocketEndpointConfig webSocketEndpointConfig, EventExecutorGroup eventExecutorGroup) throws SSLException {
        this.stompWebSocketEndpointEventServer = stompWebSocketEndpointEventServer;
        this.webSocketEndpointConfig = webSocketEndpointConfig;
        this.eventExecutorGroup = eventExecutorGroup;
        init();
    }

    private void init() throws SSLException {
        // SSL配置
        if (!ObjectUtils.isEmpty(webSocketEndpointConfig.getKeyStore())) {
            // 创建SSL上下文
            sslContext = SslUtils.createSslContext(webSocketEndpointConfig.getKeyPassword(), webSocketEndpointConfig.getKeyStore(), webSocketEndpointConfig.getKeyStoreType(), webSocketEndpointConfig.getKeyStorePassword(), webSocketEndpointConfig.getTrustStore(), webSocketEndpointConfig.getTrustStoreType(), webSocketEndpointConfig.getTrustStorePassword());
        } else {
            // 如果没有配置KeyStore，则SSL上下文为空
            sslContext = null;
        }
        // 跨域配置
        corsConfig = createCorsConfig(webSocketEndpointConfig.getCorsOrigins(), webSocketEndpointConfig.getCorsAllowCredentials());
    }

    /**
     * 创建跨域请求配置
     */
    private CorsConfig createCorsConfig(String[] corsOrigins, Boolean corsAllowCredentials) {
        // 如果corsOrigins数组为空，则返回null
        if (ObjectUtils.isEmpty(corsOrigins)) {
            return null;
        }
        // 根据corsOrigins数组的内容创建CorsConfigBuilder对象
        // 如果corsOrigins中包含"*"，则使用CorsConfigBuilder.forAnyOrigin()
        // 否则，使用CorsConfigBuilder.forOrigins(corsOrigins)
        CorsConfigBuilder corsConfigBuilder = Arrays.stream(corsOrigins).anyMatch("*"::equals) ? CorsConfigBuilder.forAnyOrigin() : CorsConfigBuilder.forOrigins(corsOrigins);
        // 如果corsAllowCredentials不为null且为true，则允许发送credentials
        if (corsAllowCredentials != null && corsAllowCredentials) {
            corsConfigBuilder.allowCredentials();
        }
        // 允许空来源
        corsConfigBuilder.allowNullOrigin();
        // 构建并返回CorsConfig对象
        return corsConfigBuilder.build();
    }

    @Override
    protected void initChannel(Channel channel) throws Exception {
        // 获取当前Channel的Pipeline
        ChannelPipeline pipeline = channel.pipeline();
        // 如果配置了空闲超时时间，则添加IdleStateHandler
        if (webSocketEndpointConfig.getReaderIdleTimeSeconds() != 0 ||
                webSocketEndpointConfig.getWriterIdleTimeSeconds() != 0 ||
                webSocketEndpointConfig.getAllIdleTimeSeconds() != 0) {
            // 添加IdleStateHandler以处理空闲超时
            pipeline.addLast(IDLE_TIMEOUT, new IdleStateHandler(
                    webSocketEndpointConfig.getReaderIdleTimeSeconds(),
                    webSocketEndpointConfig.getWriterIdleTimeSeconds(),
                    webSocketEndpointConfig.getAllIdleTimeSeconds()
            ));
            pipeline.addAfter(IDLE_TIMEOUT, IDLE_ENVET, new CommonChannelIdleTimeoutHandler());
        }
        // 添加HTTP编解码器
        pipeline.addLast(HTTP_CODEC, new HttpServerCodec());
        // 添加HTTP对象聚合器，设置最大消息大小为65536字节
        pipeline.addLast(HTTP_AGGREGATOR, new HttpObjectAggregator(MAX_FRAME_SIZE.getValue()));
        // 添加分块写处理器
        pipeline.addLast(new ChunkedWriteHandler());
        //Websocket Handler配置
        // 添加WebSocket服务器协议处理器
        pipeline.addLast(WEBSOCKET_HANDLER, new WebSocketServerProtocolHandler(webSocketEndpointConfig.getPath(), // WebSocket路径
                StompVersion.SUB_PROTOCOLS));
//        pipeline.addLast(BUFF_WEBSOCKET_Decoder, new WebSocketFrameToByteBufDecoder());
//        pipeline.addLast(BUFF_WEBSOCKET_Encoder, new ByteBufToWebSocketFrameEncoder());
        //StompHandler配置
        //stomp协议解码器
        pipeline.addLast(STOMP_DECODER, new StompSubframeDecoder());
        //stomp协议编码器
        pipeline.addLast(STOMP_ENCODER, new StompSubframeEncoder());
        //stomp aggrelator
        pipeline.addLast(STOMP_AGGREGATOR, new StompSubframeAggregator(MAX_FRAME_SIZE.getValue()));
        //自定义stompx协议处理器
        pipeline.addLast(STOMP_HANDLER, new StompServerHandler2(stompWebSocketEndpointEventServer, webSocketEndpointConfig, eventExecutorGroup));
    }
}
